<html>
<head>
  <title>3.工厂方法（FactoryMethod）模式</title>
  <basefont face="微软雅黑" size="2" />
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  <meta name="exporter-version" content="YXBJ Windows/602628 (zh-CN, DDL); Windows/10.0.0 (Win64); EDAMVersion=V2;"/>
  <style>
    body, td {
      font-family: 微软雅黑;
      font-size: 10pt;
    }
  </style>
</head>
<body>
<a name="20522"/>
<h1>3.工厂方法（FactoryMethod）模式</h1>
<div>
<table bgcolor="#D4DDE5" border="0">
<tr><td><b>创建时间：</b></td><td><i>2020/4/12 7:28</i></td></tr>
<tr><td><b>更新时间：</b></td><td><i>2020/11/30 8:10</i></td></tr>
<tr><td><b>作者：</b></td><td><i>Long Life Student</i></td></tr>
</table>
</div>
<br/>

<div>
<span><div><div><span style="font-size: 14pt; font-weight: bold;">一、基本描述</span></div><ul><li><div>定义一个用于创建对象的接口，让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。</div></li><li><div>工厂方法模式是一个工厂抽象接口和多个具体生成对象的工厂，增加功能时，不需要更改原有的工厂类，只要增加相应的具体工厂即可。</div></li><li><div>工厂方法模式只在一开始实例化具体工厂类的对象时会做出选择，一旦具体工厂类确定，后续所有的操作均无需修改。</div></li><li><div>又称为工厂模式、虚拟构造器模式、多态工厂模式。</div></li><li><div>所有工厂模式都用来封装对象的创建。工厂方法模式（ Factory Method Pattern）通过让子类决定该创建的对象是什么，来达到将对象创建的过程封装的目的。</div></li><li><div>工厂方法模式能够封装具体类型的实例化。</div></li><li><div>对于定义中提到的：工厂方法让子类决定要实例化的类是哪一个。所谓的“决定”，并不是指模式允许子类本身在运行时做决定，而是指在编写创建者类时，不需要知道实际创建的产品是哪一个。选择了使用哪个子类，自然就决定了实际创建的产品是什么。</div></li><li><div>工厂方法可以封装变化：可以将创建对象的代码封装起来。实例化具体类的代码，很可能在以后经常需要变化。而工厂方法模式可以封装实例化的行为。</div></li><li><div>工厂方法模式将创建对象的代码集中在一个对象或方法中，可以避免代码中的重复，并且更方便以后的维护。这也意味着客户在实例化对象时，只会依赖于接口，而不是具体类。这可以帮助针对接口编程，而不针对实现编程。这让代码更具有弹性，可以应对未来的扩展。</div></li><li><div>与简单工厂模式的区别：参数化的工厂方法看起来很像简单工厂。</div></li><ul><li><div>简单工厂把全部的事情在一个地方处理完了</div></li><li><div>工厂方法创建一个框架，让子类决定要如何实现</div></li></ul><li><div>工厂方法模式有两种形式</div></li><ul><li><div>参数化工厂方法，它可以根据传入的参数创建不同的对象</div></li><li><div>工厂经常只产生一种对象，不需要参数化</div></li></ul></ul><div><span style="font-size: 14pt; font-weight: bold;">二、图例</span></div><div><img src="3.工厂方法（FactoryMethod）模式_files/Image.png" type="image/png" data-filename="Image.png" width="424"/></div><ul><li><div><span style="font-weight: bold;">Product</span>：工厂生产的产品。定义工厂方法锁创建的对象的接口，即对象的抽象类。负责定义产品的共性，实现对事物最抽象的定义。所有的产品必须实现这个共同的接口，这样一来，使用这些产品的类就可以引用这个接口，而不是具体类。</div></li><li><div><span style="font-weight: bold;">ConcreteProduct</span>：实现Product接口。被创建的具体的产品。</div></li><li><div><span style="font-weight: bold;">Creator</span>：这是抽象创建者类。它定义了一个抽象的工厂方法，让子类实现此方法制造产品。声明工厂方法，该方法返回一个Product类型的对象，Creator也可以定义一个工厂方法的缺省实现，它返回一个缺省的ConcreteProduct。即，Creator可以是抽象类（或接口），也可以是一个具体类，实现一个默认的工厂方法。</div><div>它实现了所有操作产品的方法，但不实现工厂方法。</div><div>创建者通常会包含依顿于抽象产品的代码，而这些抽象产品由子类制造。<span style="font-size: unset; color: unset; font-family: unset;">创建者不需要真的知道在</span>制造<span style="font-size: unset; color: unset; font-family: unset;">哪种具体产品。</span></div></li></ul><div style="margin-left: 40px;">工厂方法：</div><ul><ul><li><div>工厂方法用来处理对象的创建，并将这样的行为封装在子类中。这样，客户程序中关于超类的代码就和子类对象创建代码解耦了。</div></li><li><div>工厂方法可能需要参数（也可能不需要），来指定所要的产品。</div></li><li><div>工厂方法将客户和实际创建具体产品的代码分割开来。</div></li></ul><li><div><span style="font-weight: bold;">ConcreteCreator</span>：能够产生产品的类称为具体创建者。重定义工厂方法以返回一个ConcreteProduct实例。是具体的创建类，与ConcreteProduct一一对应。实际使用时，除了创建产品对象外，还可负责产品对象的初始化工作以及一些资源与环境配置工作。</div><div>当只有一个 ConcreteCreator 的时候，工厂方法模式依然很有用，因为它帮助我们将产品的“实现”从“使用”中解耦。如果增加产品或者改变产品的实现， Creator并不会受到影响。</div></li></ul><div>下图也是工厂方法模式的图例，可以更清晰的理解工厂方法中的“一一对应”的关系。</div><div><img src="3.工厂方法（FactoryMethod）模式_files/Image [1].png" type="image/png" data-filename="Image.png" width="558"/></div><ul><li><div>平行的类层级</div><div>产品类和创建者类层级是平行的。</div><div>因为它们都有抽象类，而抽象类都有许多具体的子类，每个子类都有自己特定的实现。</div></li></ul><div><span style="font-size: 14pt; font-weight: bold;">三、优缺点</span></div><div><span style="font-weight: bold;">优点：</span></div><ul><li><div>良好的封装性，代码结构清晰。（对产品的创建过程进行封装）</div></li><li><div>扩展性很好。符合“开闭原则”。</div></li><li><div>屏蔽产品类。（只需要关心产品的接口，在数据库开发中很好的应用了这一模式）</div></li><li><div>工厂方法模式是典型的解耦框架。基于工厂角色和产品角色的多态性设计是工厂方法模式的关键，可以让工厂自主确定创建何种产品。</div></li></ul><div><span style="font-weight: bold;">缺点：</span></div><ul><li><div>具体产品类与工厂类一一对应，新增类时，类的个数成对增加。</div></li><li><div>考虑可扩展性，需引入抽象层，在客户端代码中均使用抽象层进行操作，相对而言，增加了系统的抽象性和理解难度。</div></li></ul><div><span style="font-size: 14pt; font-weight: bold;">四、可能的改进</span></div><ol><li><div><span style="font-size: 16px; letter-spacing: normal; orphans: 4; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><a href="https://github.com/PhycheLiu/DesignPattern_Study-Test/tree/master/Java/src/com/company/factory_method/section1" style="font-size: 16px; font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif; font-variant-caps: normal; font-variant-ligatures: normal;">使用模板和反射的方法，改进工厂方法模式。</a></span></div></li><li><div><span style="font-size: 16px; letter-spacing: normal; orphans: 4; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif; font-variant-caps: normal; font-variant-ligatures: normal;"><a href="https://github.com/PhycheLiu/DesignPattern_Study-Test/tree/master/Java/src/com/company/factory_method/section3" style="font-size: 16px; font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif; font-variant-caps: normal; font-variant-ligatures: normal;">将工厂方法缩小为简单工厂模式。</a>也即所谓的简单工厂模式。</span></div></li><li><div><span style="color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;;">使用XML和反射机制确定使用哪个具体工厂类。</span></div></li></ol><div><span style="font-size: 14pt; font-weight: bold;">五、个人理解</span></div><ul><li><div>工厂方法模式是最常用、最基础的创建型设计模式，有很好的扩展性和封装性，在选择创建型模式的时候，应当首先想到工厂方法模式。</div></li><li><div>工厂方法模式最基本的架构是一个具体产品类对应一个具体的工厂类，但是有多个变种，甚至所谓的简单工厂模式也是工厂方法模式的一个变种。</div></li><li><div>工厂方法模式的主要思路是将创建对象的职责与知识集中起来。</div></li></ul><div><br/></div></div><div><br/></div></span>
</div></body></html> 